﻿using System;
using System.Collections.Generic;
using TrueSync;

namespace HEFramework
{
    public static class AttributeComponentSystem
    {
        [EntitySystem]
        public class AttributeComponentAwakeSystem : AwakeSystem<AttributeComponent, int, int>
        {
            protected override void Awake(AttributeComponent _self, int _attributeID, int _teamID)
            {
                var dc = _self.GetSceneChild<DataTableComponent>();
                _self.Attribute = dc.LoadDataTable<DRAttribute>().GetData(_attributeID);

                _self.HP = _self.Attribute.X_HP;
                _self.MP = _self.Attribute.X_MP;

                _self.X_HP = new(_self.Attribute.X_HP);
                _self.X_MP = new(_self.Attribute.X_MP);

                _self.REC_HP = new(_self.Attribute.REC_HP);
                _self.REC_MP = new(_self.Attribute.REC_MP);

                _self.P_ATK = new(_self.Attribute.P_ATK);
                _self.M_ATK = new(_self.Attribute.M_ATK);
                _self.P_DEF = new(_self.Attribute.P_DEF);
                _self.M_DEF = new() { _self.Attribute.M_DEF };

                _self.P_ATK_SP = new(_self.Attribute.P_ATK_SP);
                _self.M_ATK_SP = new() { _self.Attribute.M_ATK_SP };
                _self.MV_SP = new(_self.Attribute.MV_SP);

                _self.P_ATK_RAG = _self.Attribute.P_ATK_RAG;
                _self.P_ATK_BAT = _self.Attribute.P_ATK_BAT;
                _self.P_ATK_AT = _self.Attribute.P_ATK_BAT;
                _self.P_ATK_DP = _self.Attribute.P_ATK_DP;
                _self.P_ATK_EP = _self.Attribute.P_ATK_BAT - _self.Attribute.P_ATK_DP - _self.Attribute.P_ATK_DBS;
                _self.P_ATK_DBS = _self.Attribute.P_ATK_DBS;
                _self.M_ATK_CP = _self.Attribute.M_ATK_CP;
                _self.M_ATK_CBS = _self.Attribute.M_ATK_CBS;

                _self.TRT = _self.Attribute.TRT;
                _self.DOG = new() { };

                _self.P_VP = 0;
                _self.M_VP = 0;
                _self.P_CRT = 0;
                _self.M_CRT = 0;
                _self.P_CRT_ADD = 200;
                _self.M_CRT_ADD = 200;

                _self.EXP = 0;
                _self.EXP_R = 100;

                _self.LV = _self.Attribute.LV;
                _self.RANK = _self.Attribute.RANK;
                _self.T_ID = _teamID;
                _self.Change_ATK_SP();
            }
        }


        public static void OnDamage(this AttributeComponent _self, AttributeComponent _a, FP _value, ePowerType _type = ePowerType.Physics, bool _isMissOpen = false)
        {
            if (_type == ePowerType.None)
            {
                return;
            }

            if (_value < 0)
            {
                _value = 0;
            }

            FP value = _value;
            FP vp_value;
            ePowerType powerType = _type;
            bool isCtr = false;
            bool isMiss = false;

            if (_isMissOpen)
            {
                //计算是否闪避
                isMiss = Formula.DOG(_self.DOG);
            }

            //是否触发了闪避
            if (!isMiss)
            {
                switch (powerType)
                {
                    case ePowerType.Physics:

                        //存在施加者的情况
                        if (_a != null)
                        {
                            //是否攻击暴击
                            isCtr = Formula.CTR(_a.P_CRT);
                            if (isCtr)
                            {
                                value = Formula.RA(value, _a.P_CRT_ADD);
                            }
                        }

                        value = Formula.PDG(value, _self.P_DEF.Value);

                        if (_a != null)
                        {
                            //吸血
                            vp_value = Formula.RA(value, _self.P_VP);
                            if (vp_value != 0)
                            {
                                _a.OnHM(vp_value, 0);
                            }
                        }

                        break;
                    case ePowerType.Magic:

                        //存在施加者的情况
                        if (_a != null)
                        {
                            //是否法术暴击
                            isCtr = Formula.CTR(_a.M_CRT);
                            if (isCtr)
                            {
                                value = Formula.RA(value, _a.M_CRT_ADD);
                            }
                        }

                        value = Formula.MDG(value, _self.M_DEF);

                        if (_a != null)
                        {
                            //吸血
                            vp_value = Formula.RA(value, _self.M_VP);
                            if (vp_value != 0)
                            {
                                _a.OnHM(vp_value, 0);
                            }
                        }

                        break;
                }
            }
            else
            {
                value = 0;
            }

            //数据记录
            var sc = _self.GetSceneChild<Statistic>();
            var tc = _self.GetParentChild<TransformComponent>();
            if (sc != null && tc != null)
            {
                int aID;
                if (_a != null)
                {
                    aID = _a.Attribute.ID;
                }
                else
                {
                    aID = -1;
                }

                sc.Statistic(tc.P, aID, _self.Attribute.ID, powerType, isCtr, isMiss, -value, 0, true);
            }


            _self.Change_HP(-value);
        }

        public static void OnHealth(this AttributeComponent _self, AttributeComponent _a, FP _valueA, FP _valueB, ePowerType _type = ePowerType.Physics)
        {
            if (_valueA < 0)
            {
                _valueA = 0;
            }

            if (_valueB < 0)
            {
                _valueA = 0;
            }

            FP hp_value = _valueA;
            FP mp_value = _valueB;
            ePowerType powerType = _type;
            bool isCtr = false;
            bool isMiss = false;

            if (_a != null)
            {
                //根据类型决定暴击计算
                switch (powerType)
                {
                    case ePowerType.Physics:
                        isCtr = Formula.CTR(_a.P_CRT);
                        if (isCtr)
                        {
                            hp_value = hp_value == 0 ? 0 : Formula.RA(hp_value, _a.P_CRT_ADD);
                            mp_value = mp_value == 0 ? 0 : Formula.RA(mp_value, _a.P_CRT_ADD);
                        }

                        break;
                    case ePowerType.Magic:
                        isCtr = Formula.CTR(_a.M_CRT);
                        if (isCtr)
                        {
                            hp_value = hp_value == 0 ? 0 : Formula.RA(hp_value, _a.M_CRT_ADD);
                            mp_value = mp_value == 0 ? 0 : Formula.RA(mp_value, _a.M_CRT_ADD);
                        }

                        break;
                }
            }

            //数据记录
            var sc = _self.GetSceneChild<Statistic>();
            var tc = _self.GetParentChild<TransformComponent>();
            if (sc != null && tc != null)
            {
                int aID;
                if (_a != null)
                {
                    aID = _a.Attribute.ID;
                }
                else
                {
                    aID = -1;
                }

                sc.Statistic(tc.P, aID, _self.Attribute.ID, powerType, isCtr, isMiss, hp_value, mp_value, true);
            }

            _self.Change_HP(hp_value);
            _self.Change_MP(mp_value);
        }

        public static void OnHM(this AttributeComponent _self, FP _valueA, FP _valueB, bool _isStatistic = true)
        {
            FP hp_value = _valueA;
            FP mp_value = _valueB;

            if (_isStatistic)
            {
                //数据记录
                var sc = _self.GetSceneChild<Statistic>();
                var tc = _self.GetParentChild<TransformComponent>();
                if (sc != null && tc != null)
                {
                    sc.Statistic(tc.P, _self.Attribute.ID, _self.Attribute.ID, ePowerType.None, false, false, hp_value, mp_value, false);
                }
            }

            _self.Change_HP(hp_value);
            _self.Change_MP(mp_value);
        }


        #region 属性调整

        public static void Change_HP(this AttributeComponent _self, FP _value)
        {
            _self.HP += _value;

            if (_self.HP > _self.X_HP.Value)
            {
                _self.HP = _self.X_HP.Value;
            }

            if (_self.HP < 0)
            {
                _self.HP = 0;
            }
        }

        public static void Change_MP(this AttributeComponent _self, FP _value)
        {
            _self.MP += _value;

            if (_self.MP > _self.X_MP.Value)
            {
                _self.MP = _self.X_MP.Value;
            }

            if (_self.MP < 0)
            {
                _self.MP = 0;
            }
        }

        public static void Change_X_HP(this AttributeComponent _self, FP _value)
        {
            FP old = _self.X_HP.Value;
            _self.X_HP.ChangeAdd(_value);
            //修正比例
            var dif = Formula.Dif(_self.HP, old, _self.X_HP.Value);
            _self.Change_HP(dif);
        }

        public static void Change_X_HP_PCT(this AttributeComponent _self, FP _value)
        {
            FP old = _self.X_HP.Value;
            _self.X_HP.ChangePctAdd(_value);
            //修正比例
            var dif = Formula.Dif(_self.HP, old, _self.X_HP.Value);
            _self.Change_HP(dif);
        }

        public static void Change_X_MP(this AttributeComponent _self, FP _value)
        {
            FP old = _self.X_MP.Value;
            _self.X_MP.ChangeAdd(_value);
            //修正比例
            var dif = Formula.Dif(_self.MP, old, _self.X_MP.Value);
            _self.Change_MP(dif);
        }

        public static void Change_X_MP_PCT(this AttributeComponent _self, FP _value)
        {
            FP old = _self.X_MP.Value;
            _self.X_MP.ChangePctAdd(_value);
            //修正比例
            var dif = Formula.Dif(_self.MP, old, _self.X_MP.Value);
            _self.Change_MP(dif);
        }


        public static void Change_REC_HP(this AttributeComponent _self, FP _value)
        {
            _self.REC_HP.ChangeAdd(_value);
        }

        public static void Change_REC_HP_PCT(this AttributeComponent _self, FP _value)
        {
            _self.REC_HP.ChangePctAdd(_value);
        }

        public static void Change_REC_MP(this AttributeComponent _self, FP _value)
        {
            _self.REC_MP.ChangeAdd(_value);
        }

        public static void Change_REC_MP_PCT(this AttributeComponent _self, FP _value)
        {
            _self.REC_MP.ChangePctAdd(_value);
        }


        public static void Change_P_ATK(this AttributeComponent _self, FP _value)
        {
            _self.P_ATK.ChangeAdd(_value);
        }

        public static void Change_P_ATK_PCT(this AttributeComponent _self, FP _value)
        {
            _self.P_ATK.ChangePctAdd(_value);
        }

        public static void Change_M_ATK(this AttributeComponent _self, FP _value)
        {
            _self.M_ATK.ChangeAdd(_value);
        }

        public static void Change_M_ATK_PCT(this AttributeComponent _self, FP _value)
        {
            _self.M_ATK.ChangePctAdd(_value);
        }

        public static void Change_P_DEF(this AttributeComponent _self, FP _value)
        {
            _self.P_DEF.ChangeAdd(_value);
        }

        public static void Change_P_DEF_PCT(this AttributeComponent _self, FP _value)
        {
            _self.P_DEF.ChangePctAdd(_value);
        }

        public static void Change_M_DEF(this AttributeComponent _self, FP _value)
        {
            _self.ChangeUnLineValue(_self.M_DEF, _value);
        }


        public static void Change_P_ATK_SP(this AttributeComponent _self, FP _value)
        {
            _self.P_ATK_SP.ChangeAdd(_value);
            _self.Change_ATK_SP();
        }

        public static void Change_P_ATK_SP_PCT(this AttributeComponent _self, FP _value)
        {
            _self.P_ATK_SP.ChangePctAdd(_value);
            _self.Change_ATK_SP();
        }

        public static void Change_M_ATK_SP(this AttributeComponent _self, FP _value)
        {
            _self.ChangeUnLineValue(_self.M_ATK_SP, _value);
        }

        public static void Change_P_ATK_RAG(this AttributeComponent _self, FP _value)
        {
            _self.P_ATK_RAG += _value;
        }

        public static void Change_DOG(this AttributeComponent _self, FP _value)
        {
            _self.ChangeUnLineValue(_self.DOG, _value);
        }

        public static void Change_TRT(this AttributeComponent _self, FP _value)
        {
            _self.TRT += _value;
        }


        public static void Change_P_VP(this AttributeComponent _self, FP _value)
        {
            _self.P_VP += _value;
        }

        public static void Change_M_VP(this AttributeComponent _self, FP _value)
        {
            _self.M_VP += _value;
        }

        public static void Change_P_CRT(this AttributeComponent _self, FP _value)
        {
            _self.P_CRT += _value;
        }

        public static void Change_M_CRT(this AttributeComponent _self, FP _value)
        {
            _self.M_CRT += _value;
        }

        public static void Change_P_CRT_ADD(this AttributeComponent _self, FP _value)
        {
            _self.P_CRT_ADD += _value;
        }

        public static void Change_M_CRT_ADD(this AttributeComponent _self, FP _value)
        {
            _self.M_CRT_ADD += _value;
        }


        public static void Change_EXP(this AttributeComponent _self, FP _value)
        {
            FP value = _value;
            if (value > 0)
            {
                //满级后不再获得经验
                if (_self.Is_X_LV())
                {
                    return;
                }

                value = Formula.RA(value, _self.EXP_R);
            }

            _self.EXP += value;

            if (_self.EXP < 0)
            {
                _self.EXP = 0;
                return;
            }

            _self.Change_EXP();
        }

        public static void Change_EXP_R(this AttributeComponent _self, FP _value)
        {
            _self.EXP_R += _value;
        }

        public static void Change_LV(this AttributeComponent _self, int _value)
        {
            int old_lv = _self.LV;
            int new_lv = _self.LV + _value;
            _self.EXP = 0;
            int dif = new_lv - old_lv;
            if (dif > 0)
            {
                for (int i = 0; i < dif; i++)
                {
                    //满级跳出循环
                    if (_self.Is_X_LV())
                    {
                        break;
                    }

                    _self.LV += 1;
                    _self.ChangeUp_LV();
                }
            }
            else
            {
                for (int i = 0; i < -dif; i++)
                {
                    //初始等级跳出循环
                    if (_self.LV <= 0)
                    {
                        break;
                    }

                    _self.LV -= 1;
                }
            }
        }

        public static void Change_RANK(this AttributeComponent _self, int _value)
        {
            int old_rank = _self.RANK;
            int new_rank = _self.RANK + _value;
            int dif = new_rank - old_rank;
            //升阶
            if (dif > 0)
            {
                for (int i = 0; i < dif; i++)
                {
                    //满星后提升属性
                    if (_self.Is_X_RANK())
                    {
                        _self.ChangeMax_RANK();
                        continue;
                    }

                    _self.RANK += 1;
                    _self.ChangeUp_RANK();
                }
            }
            else
            {
                for (int i = 0; i < -dif; i++)
                {
                    //初始星级跳出循环
                    if (_self.RANK <= 0)
                    {
                        break;
                    }

                    _self.RANK -= 1;
                }
            }
        }

        public static void Change_T_ID(this AttributeComponent _self, int _value)
        {
            _self.T_ID = _value;
        }

        #endregion

        /// <summary>
        /// 改变攻击速度
        /// </summary>
        /// <returns></returns>
        private static void Change_ATK_SP(this AttributeComponent _self)
        {
            FP ias = _self.P_ATK_SP.Value;
            FP bat = _self.P_ATK_BAT;
            FP dp = _self.Attribute.P_ATK_DP;
            FP ep = _self.Attribute.P_ATK_BAT - _self.Attribute.P_ATK_DP - _self.Attribute.P_ATK_DBS;
            FP dbs = _self.Attribute.P_ATK_DBS;
            FP scale = 1 + ias / 100;
            _self.P_ATK_AT = bat / scale;
            _self.P_ATK_DP = dp / scale;
            _self.P_ATK_EP = ep / scale;
            _self.P_ATK_DBS = dbs / scale;
        }

        private static void Change_EXP(this AttributeComponent _self)
        {
            var dc = _self.GetSceneChild<DataTableComponent>();
            if (dc == null)
            {
                return;
            }

            var table = dc.LoadDataTable<DRLevel>();
            var lv_data = table.GetData(_self.Attribute.LV_ID);

            while (true)
            {
                //满级了直接跳出处理
                if (_self.Is_X_LV())
                {
                    _self.EXP = 0;
                    break;
                }

                FP lv_exp = lv_data.Exps[_self.LV];
                FP exp = _self.EXP - lv_exp;
                if (exp >= 0)
                {
                    _self.Change_LV(1);
                    _self.EXP = exp;
                }
                else
                {
                    //不够升级跳出循环
                    break;
                }
            }
        }

        private static void ChangeUp_LV(this AttributeComponent _self)
        {
            var reward = _self.GetSceneChild<Reward>();
            var dc = _self.GetSceneChild<DataTableComponent>();
            if (reward == null || dc == null)
            {
                return;
            }

            var table = dc.LoadDataTable<DRLevel>();
            //提升属性
            var lvs = table.GetData(_self.Attribute.LV_ID);
            for (int i = 0; i < lvs.RewardIDs.Length; i++)
            {
                reward.ChangeReward(_self.Parent, lvs.RewardIDs[i], lvs.RewardValues[i]);
            }
        }

        private static void ChangeUp_RANK(this AttributeComponent _self)
        {
            var reward = _self.GetSceneChild<Reward>();
            var dc = _self.GetSceneChild<DataTableComponent>();
            if (reward == null || dc == null)
            {
                return;
            }

            var table = dc.LoadDataTable<DRRank>();
            //提升属性
            var ranks = table.GetData(_self.Attribute.RANK_ID);
            for (int i = 0; i < ranks.RewardIDs.Length; i++)
            {
                reward.ChangeReward(_self.Parent, ranks.RewardIDs[i], ranks.RewardValues[i]);
            }
        }

        private static void ChangeMax_RANK(this AttributeComponent _self)
        {
            var reward = _self.GetSceneChild<Reward>();
            var dc = _self.GetSceneChild<DataTableComponent>();
            if (reward == null || dc == null)
            {
                return;
            }

            var table = dc.LoadDataTable<DRRank>();
            //提升属性
            var ranks = table.GetData(_self.Attribute.RANK_ID);
            for (int i = 0; i < ranks.RewardID2s.Length; i++)
            {
                reward.ChangeReward(_self.Parent, ranks.RewardID2s[i], ranks.RewardValue2s[i]);
            }
        }

        public static bool Is_X_LV(this AttributeComponent _self)
        {
            return _self.LV == _self.Attribute.X_LV;
        }

        public static bool Is_X_RANK(this AttributeComponent _self)
        {
            return _self.RANK == _self.Attribute.X_RANK;
        }

        public static bool IsSelf(this AttributeComponent _self, AttributeComponent _other)
        {
            return _self.InstanceID == _other.InstanceID;
        }

        public static bool IsTeam(this AttributeComponent _self, AttributeComponent _other)
        {
            var camp = _self.GetSceneChild<Camp>();
            if (camp == null)
            {
                return _self.T_ID == _other.T_ID;
            }

            return camp.IsTeam(_self.T_ID, _other.T_ID);
        }

        public static bool IsTeam(this AttributeComponent _self, int _otherID)
        {
            var camp = _self.GetSceneChild<Camp>();
            if (camp == null)
            {
                return _self.T_ID == _otherID;
            }

            return camp.IsTeam(_self.T_ID, _otherID);
        }

        public static bool IsFriend(this AttributeComponent _self, AttributeComponent _other)
        {
            var camp = _self.GetSceneChild<Camp>();
            if (camp == null)
            {
                return false;
            }

            return camp.IsFriend(_self.T_ID, _other.T_ID);
        }

        public static bool IsFriend(this AttributeComponent _self, int _otherID)
        {
            var camp = _self.GetSceneChild<Camp>();
            if (camp == null)
            {
                return false;
            }

            return camp.IsFriend(_self.T_ID, _otherID);
        }

        public static bool IsEnemy(this AttributeComponent _self, AttributeComponent _other)
        {
            var camp = _self.GetSceneChild<Camp>();
            if (camp == null)
            {
                return false;
            }

            return camp.IsEnemy(_self.T_ID, _other.T_ID);
        }

        public static bool IsEnemy(this AttributeComponent _self, int _otherID)
        {
            var camp = _self.GetSceneChild<Camp>();
            if (camp == null)
            {
                return false;
            }

            return camp.IsEnemy(_self.T_ID, _otherID);
        }

        public static FP LV_EXP_PCT(this AttributeComponent _self)
        {
            if (_self.Is_X_LV())
            {
                return 1;
            }

            var dc = _self.GetSceneChild<DataTableComponent>();
            if (dc == null)
            {
                return 0;
            }

            var table = dc.LoadDataTable<DRLevel>();
            var lv_data = table.GetData(_self.Attribute.LV_ID);

            FP exp = lv_data.Exps[_self.LV];
            FP pct = _self.EXP / exp;

            if (pct >= 1)
            {
                pct = 1;
            }

            if (pct <= 0)
            {
                pct = 0;
            }

            return pct;
        }


        public static FP GetValue(this AttributeComponent _attribute, int _type, FP _value)
        {
            switch (_type)
            {
                case (int)eAttribute.HP:
                    return _attribute.HP;
                case (int)eAttribute.HP_PCT:
                    return _attribute.HP * Formula.PCT(_value);
                case (int)eAttribute.X_HP:
                    return _attribute.X_HP.Value;
                case (int)eAttribute.X_HP_PCT:
                    return _attribute.X_HP.Value * Formula.PCT(_value);
                case (int)eAttribute.MP:
                    return _attribute.MP;
                case (int)eAttribute.MP_PCT:
                    return _attribute.MP * Formula.PCT(_value);
                case (int)eAttribute.X_MP:
                    return _attribute.X_MP.Value;
                case (int)eAttribute.X_MP_PCT:
                    return _attribute.X_MP.Value * Formula.PCT(_value);
                case (int)eAttribute.P_ATK:
                    return _attribute.P_ATK.Value;
                case (int)eAttribute.P_ATK_PCT:
                    return _attribute.P_ATK.Value * Formula.PCT(_value);
                case (int)eAttribute.M_ATK:
                    return _attribute.M_ATK.Value;
                case (int)eAttribute.M_ATK_PCT:
                    return _attribute.M_ATK.Value * Formula.PCT(_value);
                case (int)eAttribute.LV:
                    return _attribute.LV;
                case (int)eAttribute.RANK:
                    return _attribute.RANK;
            }

            return 0;
        }


        /// <summary>
        /// 变动非线性值
        /// </summary>
        /// <param name="_attribute"></param>
        /// <param name="_list"></param>
        /// <param name="_value"></param>
        private static void ChangeUnLineValue(this AttributeComponent _attribute, List<FP> _list, FP _value)
        {
            //如果成功移除相反值，则不加
            if (!_list.Remove(_value * -1))
            {
                _list.Add(_value);
            }
        }
    }
}